// Contient toutes les spécifications de classes nécessaires
// pour représenter l'arbre abstrait
#ifndef ARBRE_H_
#define ARBRE_H_

#include <vector>
#include <iostream>
#include <iomanip>
#include <typeinfo>
using namespace std;

#include "Symbole.h"

////////////////////////////////////////////////////////////////////////////////

class Noeud {
    // classe abstraite dont dériveront toutes les classes servant à représenter l'arbre abstrait
    // Remarque : la classe ne contient aucun constructeur
public:
    virtual int getValeur() = 0; // méthode pure (non implémentée) qui rend la classe abstraite

    virtual void afficher(unsigned short indentation = 0) {
        cout << setw(4 * indentation) << " ";
    }

    virtual void genCode(ostream &f, unsigned short indentation = 0) {
        for (int i = 0; i < indentation; i++)
            f << "    ";
    }

    virtual ~Noeud() {
    } // présence d'un destructeur virtuel conseillée dans les classes abstraites
};

////////////////////////////////////////////////////////////////////////////////

class NoeudSeqInst : public Noeud {
    // classe pour représenter un noeud "sequence d'instruction"
    // qui a autant de fils que d'instructions dans la séquence
public:
    NoeudSeqInst(); // construit une séquence d'instruction vide

    ~NoeudSeqInst() {
    } // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue chaque instruction de la séquence
    void afficher(unsigned short indentation = 0); // affiche la séquence d'instructions
    void ajouteInstruction(Noeud* instruction); // ajoute une instruction à la séquence
    void genCode(ostream &f, unsigned short indentation = 0);

private:
    vector<Noeud *> tabInst; // pour stocker les instructions de la séquence
};

////////////////////////////////////////////////////////////////////////////////

class NoeudAffectation : public Noeud {
    // classe pour représenter un noeud "affectation"
    // composé de 2 fils : la variable et l'expression qu'on lui affecte
public:
    NoeudAffectation(Noeud* variable, Noeud* expression); // construit une affectation

    ~NoeudAffectation() {
    } // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void afficher(unsigned short indentation = 0); // affiche l'affectation
    void genCode(ostream &f, unsigned short indentation = 0);

private:
    Noeud* variable;
    Noeud* expression;
};

////////////////////////////////////////////////////////////////////////////////

class NoeudOperateurBinaire : public Noeud {
    // classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
    // et de 2 fils : l'opérande gauche et l'opérande droit
public:
    NoeudOperateurBinaire(Symbole operateur, Noeud* operandeGauche, Noeud* operandeDroit);
    // construit une opération binaire : operandeGauche operateur OperandeDroit

    ~NoeudOperateurBinaire() {
    } // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation = 0); // affiche l'opération
    void genCode(ostream &f, unsigned short indentation = 0);

private:
    Symbole operateur;
    Noeud* operandeGauche;
    Noeud* operandeDroit;
};


////////////////////////////////////////////////////////////////////////////////

class NoeudInstSi : public Noeud {
    // classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
    // et de 2 fils : l'opérande gauche et l'opérande droit
public:

    NoeudInstSi() {
    }
    // construit une opération binaire : operandeGauche operateur OperandeDroit

    ~NoeudInstSi() {
    } // à cause du destructeur virtuel de la classe Noeud
    int getValeur();
    int ajoute(Noeud* cond, Noeud* seq);
    void afficher(unsigned short indentation = 0); // affiche l'opération
    void genCode(ostream &f, unsigned short indentation = 0);

private:
    vector<Noeud*> vectCond;
    vector<Noeud*> vectSeqInst;
};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstTq : public Noeud {
    // classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
    // et de 2 fils : l'opérande gauche et l'opérande droit
public:

    NoeudInstTq() : _exp(NULL), _seq(NULL) {
    }

    ~NoeudInstTq() {
    } // à cause du destructeur virtuel de la classe Noeud
    int getValeur();
    void afficher(unsigned short indentation = 0); // affiche l'opération

    void ajoute(Noeud* exp, Noeud* seq) {
        _exp = exp;
        _seq = seq;
    }
    void genCode(ostream &f, unsigned short indentation = 0);
private:
    Noeud* _exp;
    Noeud* _seq;
};
////////////////////////////////////////////////////////////////////////////////

class NoeudInstRepeter : public Noeud {
    // classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
    // et de 2 fils : l'opérande gauche et l'opérande droit
public:

    NoeudInstRepeter() : _seq(NULL), _exp(NULL) {
    }

    ~NoeudInstRepeter() {
    } // à cause du destructeur virtuel de la classe Noeud
    int getValeur();
    void afficher(unsigned short indentation = 0);

    void ajoute(Noeud*seq, Noeud*exp) {
        _exp = exp;
        _seq = seq;
    }
    void genCode(ostream &f, unsigned short indentation = 0);
private:
    Noeud * _seq;
    Noeud * _exp;

};
////////////////////////////////////////////////////////////////////////////////

class NoeudInstLire : public Noeud {
public:

    NoeudInstLire() : variable(NULL) {
    }

    ~NoeudInstLire() {
    } // à cause du destructeur virtuel de la classe Noeud
    int getValeur();
    void afficher(unsigned short indentation = 0); // affiche l'opération
    void ajoute(Noeud*var);
    void genCode(ostream &f, unsigned short indentation = 0);

private:
    Noeud* variable;
};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstEcrire : public Noeud {
    // classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
    // et de 2 fils : l'opérande gauche et l'opérande droit
public:

    NoeudInstEcrire() : ecrit(NULL) {
    }
    // construit une opération binaire : operandeGauche operateur OperandeDroit

    ~NoeudInstEcrire() {
    } // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation = 0); // affiche l'opération
    void ajoute(Noeud*var);
    void genCode(ostream &f, unsigned short indentation = 0);

private:
    Noeud* ecrit;
};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstPour : public Noeud {
    // classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
    // et de 2 fils : l'opérande gauche et l'opérande droit
public:

    NoeudInstPour() : _affect1(NULL), _affect2(NULL), _exp(NULL), _seq(NULL) {
    }
    // construit une opération binaire : operandeGauche operateur OperandeDroit

    ~NoeudInstPour() {
    } // à cause du destructeur virtuel de la classe Noeud
    int getValeur();
    void afficher(unsigned short indentation = 0);
    void ajoute(Noeud* affect1, Noeud* exp, Noeud* affect2, Noeud* seq);
    void genCode(ostream &f, unsigned short indentation = 0);

private:
    Noeud* _affect1;
    Noeud* _affect2;
    Noeud* _exp;
    Noeud* _seq;
};


////////////////////////////////////////////////////////////////////////////////

class NoeudRetour : public Noeud {
    // classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
    // et de 2 fils : l'opérande gauche et l'opérande droit
public:
    NoeudRetour(Noeud * exp) : expression(exp) {}
    // construit une opération binaire : operandeGauche operateur OperandeDroit
    ~NoeudRetour() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(){
        return expression->getValeur();
    }
    void afficher(unsigned short indentation = 0);
    void genCode(ostream &f, unsigned short indentation = 0);

private:
    Noeud* expression;
};


////////////////////////////////////////////////////////////////////////////////

class NoeudFonction : public Noeud {
    // classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
    // et de 2 fils : l'opérande gauche et l'opérande droit
public:
    NoeudFonction(void* l) : lf(l) {}
    // construit une opération binaire : operandeGauche operateur OperandeDroit
    ~NoeudFonction() {} // à cause du destructeur virtuel de la classe Noeud
    void ajoute(Noeud *param){
        vectParam.push_back(param);
    }
    int getValeur();
    void afficher(unsigned short indentation = 0);
    void genCode(ostream &f, unsigned short indentation = 0);

private:
    void* lf; // lecteur fichier
    vector<Noeud*> vectParam;
};

#endif /* ARBRE_H_ */